package com.personal.dataconvert;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.poi.ss.usermodel.Workbook;

import com.personal.core.data.DataRow;
import com.personal.core.data.DataTable;
import com.personal.core.utils.Assert;
import com.personal.dataconvert.bean.CombineColumnConfig;
import com.personal.dataconvert.bean.HeaderConfig;
import com.personal.dataconvert.bean.SheetConfig;
import com.personal.dataconvert.bean.WorkBookConfig;
import com.personal.dataconvert.port.Data2Excel;
import com.personal.dataconvert.util.ExcelHtmlUtil;

/**
 * 把规则报表按照合并配置转正不规则报表导出 tag ：可以设置居左居右的样式 dataType : 中可以设置宽度 DataRow 中可以加
 * columnName + TDSTYLE 设置单元格样式 DataRow 中可以加 columnName + TDPOSTIL 设置单元格批注
 * 左右页眉放在DataTable 中的 tag 中，格式：LEFT:xxx,RIGHT:xxx
 * @author cuibo
 */
public class IrregularDataTable2Excel implements Data2Excel
{
	/** 列转换配置 */
	private Set<? extends CombineColumnConfig> combineColumnConfigs;

	/** 是否创建表头和标题 */
	private boolean createHeader = true;

	// Excel类型
	private String excelType;

	// 是否冻结表头
	private boolean freezeHeader = true;

	/** 表头配置和动态注入 */
	private List<? extends HeaderConfig> headerConfigs = null;

	// DataTable数据集
	private DataTable table;

	// workBook
	private Workbook workbook;

	/** 重新计算宽度（html宽度放大至Excel） */
	private boolean recalWidth = false;

	/** 冻结列数 */
	private int freezeColIndex = -1;

	/** splitFlag 表头分割标记。默认是点 */
	private String splitFlag = ".";

	private IrregularDataTable2Excel()
	{
	}

	private IrregularDataTable2Excel(Builder builder)
	{
		this.table = builder.table;
		this.excelType = builder.excelType;
		this.freezeHeader = builder.freezeHeader;
		this.createHeader = builder.createHeader;
		this.freezeColIndex = builder.freezeColIndex;
		this.workbook = builder.workbook;
		this.splitFlag = builder.splitFlag;
		this.recalWidth = builder.recalWidth;
		this.headerConfigs = builder.headerConfigs;
		this.combineColumnConfigs = builder.combineColumnConfigs;
	}

	@Override
	public byte[] exportExcel() throws Exception
	{
		workbook = fillExcel();
		if (workbook == null)
		{
			return new byte[0];
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		workbook.write(out);
		return out.toByteArray();
	}

	@Override
	public Workbook fillExcel() throws Exception
	{
		if (table != null)
		{
			// 构建WorkBookConfig
			WorkBookConfig bookConfig = createWorkBookConfig();
			Assert.isNotNull(bookConfig, "构架WorkBookConfig失败！");
			Map<String, List<?>> allObjectData = loadAllObjectData();
			Data2Excel data2Excel = new ExportData2Excel.Builder().setExcelType(excelType).setWorkbook(workbook).setWorkBookConfig(bookConfig).setAllObjectData(allObjectData).build();
			return data2Excel.fillExcel();
		}
		return workbook;
	}

	private Map<String, List<?>> loadAllObjectData()
	{
		Map<String, List<?>> result = new HashMap<String, List<?>>();
		if (table.getRows() == null || table.getRows().isEmpty())
		{
			return result;
		}
		List<Object> singleList = new ArrayList<Object>();
		for (DataRow object : table.getRows())
		{
			singleList.add(object.getItemMap());
		}
		result.put(table.getTableName(), singleList);
		return result;
	}

	/**
	 * 创建WorkBookConfig
	 * @return
	 * @throws Exception
	 */
	private WorkBookConfig createWorkBookConfig() throws Exception
	{
		WorkBookConfig result = new WorkBookConfig();
		SheetConfig sheetConfig = result.newSheetConfig(table.getTableName());
		// 表头表列相关信息
		sheetConfig.setTitle(table.getTableName());
		sheetConfig.setFreezeColIndex(freezeColIndex);
		sheetConfig.setCreateHeader(createHeader);
		sheetConfig.setFreezeHeader(freezeHeader);
		// 合并配置
		sheetConfig.setCombineConfigs(combineColumnConfigs);

		// 看有没有手动设置表头
		if (headerConfigs == null || headerConfigs.isEmpty())
		{
			headerConfigs = ExcelHtmlUtil.createTrees(table, splitFlag);
		}
		Assert.isNotNullOrEmpty(headerConfigs, "构建" + table.getTableName() + "的表头节点失败！");
		// 设置SheetConfig并重新计算宽度
		ExcelHtmlUtil.setSheetConfig(sheetConfig, headerConfigs, recalWidth);
		sheetConfig.setLeftHeader(table.getLeftHeader());
		sheetConfig.setRightHeader(table.getRightHeader());
		sheetConfig.setTitle(table.getTitle());
		sheetConfig.setHeaderConfigs(headerConfigs);
		result.getSheetConfigs().add(sheetConfig);
		return result;
	}

	/**
	 * 建造
	 * @author cuibo
	 */
	public static class Builder
	{
		private DataTable table;
		private String excelType;
		private boolean freezeHeader = true;
		private boolean createHeader = true;
		private int freezeColIndex = -1;
		private Workbook workbook;
		private String splitFlag = ".";
		private boolean recalWidth = false;
		private List<? extends HeaderConfig> headerConfigs;
		private Set<? extends CombineColumnConfig> combineColumnConfigs;

		public Builder setDataTable(DataTable table)
		{
			this.table = table;
			return this;
		}

		public Builder setExcelType(String excelType)
		{
			this.excelType = excelType;
			return this;
		}

		public Builder setFreezeHeader(boolean freezeHeader)
		{
			this.freezeHeader = freezeHeader;
			return this;
		}

		public Builder setCreateHeader(boolean createHeader)
		{
			this.createHeader = createHeader;
			return this;
		}

		public Builder setFreezeColIndex(int freezeColIndex)
		{
			this.freezeColIndex = freezeColIndex;
			return this;
		}

		public Builder setWorkbook(Workbook workbook)
		{
			this.workbook = workbook;
			return this;
		}

		public Builder setSplitFlag(String splitFlag)
		{
			this.splitFlag = splitFlag;
			return this;
		}

		public Builder setRecalWidth(boolean recalWidth)
		{
			this.recalWidth = recalWidth;
			return this;
		}

		public Builder setCombineColumnConfigs(Set<? extends CombineColumnConfig> combineColumnConfigs)
		{
			this.combineColumnConfigs = combineColumnConfigs;
			return this;
		}

		public Builder setHeaderConfigs(List<? extends HeaderConfig> headerConfigs)
		{
			this.headerConfigs = headerConfigs;
			return this;
		}

		public IrregularDataTable2Excel build()
		{
			return new IrregularDataTable2Excel(this);
		}
	}

}
